import fs from 'fs';
import path from 'path';
import { ServerApiFile } from '../../api-file/server-api-file';
import p, { prefix } from '../../lib/p';
import { EOL } from 'os';
import { methodToCode } from '../../lib/method-to-code';
import { checkDependencies } from '../../lib/check-dependencies';
import { config } from '../../config';
import { copyTemplateFile } from '../../lib/copy-template-file';
import { ObjectCode } from '../../lib/object-code';

// API调用方法生成器
class ApiMethodGenerator {
  apiFiles: ServerApiFile[];
  apiDir: string;
  outputDir: string;
  outputFile: string;

  constructor(apiDir: string, outputDir: string) {
    this.apiFiles = ServerApiFile.fromDirectory(apiDir);
    this.apiDir = apiDir;
    this.outputDir = outputDir;
    this.outputFile = path.join(outputDir, 'index.ts');
  }

  // 生成函数参数
  generateFunctionParams(file: ServerApiFile): string[]{
    const params = [];
    // 添加路径参数
    if (file.params.length > 0) {
      params.push(...file.params.map(param => `${param}: string`));
    }
    
    if (file.usesRequestFiles) {
      params.push(`formData: FormData`);
    } else if (file.hasBodySchema) {
      params.push(`data: Zod.infer<typeof import('${file.importPath}').bodySchema>`);
    }

    if (file.usesQuerySchema) {
      params.push(`query: Zod.infer<typeof import('${file.importPath}').querySchema>`);
    }
    
    return params;
  }

  generateFunctionBody(file: ServerApiFile): string[] {
    const params = this.generateFunctionParams(file);
    
    // 生成 URL，将路径参数替换为实际值
    let url = file.routePath;
    file.params.forEach(param => {
      url = url.replace(`:${param.toLowerCase()}`, `\${${param}}`);
    });
    
    const requestOptions = [`url: \`${url}\``, `method: '${file.method}'`];
    
    // 检查是否有 FormData 参数
    const hasFormData = params.some(p => p.startsWith('formData:'));
    if (hasFormData) {
      requestOptions.push('body: formData');
    }

    // 检查是否有常规请求体
    if (file.hasBodySchema) {
      requestOptions.push('body: data');
    }

    if (!file.usesResponse) {
      requestOptions.push('json: true');
    } else {
      requestOptions.push('json: false');
    }
    
    // 检查是否有查询参数
    if (file.usesQuerySchema) {
      requestOptions.push('params: query');
    }
    
    // 生成函数名
    const functionName = this.generateMethodKey(file);
    
    const type = file.usesResponse ? 'Response' : `ReturnValueType<typeof import(\'${file.importPath}\').default>`;
    return methodToCode(functionName, params, [
      `return request<${type}>({`,
      ...p(requestOptions.map(v => `${v},`)),
      `})`
    ]);
  }

  // 构建嵌套对象结构
  buildNestedStructure(routes: ServerApiFile[]) {
    // 按路径分组路由
    const routeGroups = this.groupRoutesByPath(routes);
    const objectCode = new ObjectCode();

    Object.entries(routeGroups).forEach(([groupPath, groupRoutes]) => {
      const pathParts = groupPath.split('/').filter(part => part).map(part => this.toCamelCase(part));
      groupRoutes.forEach(route => {
        objectCode.add(pathParts, this.generateFunctionBody(route));
      });
    });
    return objectCode;
  }

  // 按路径分组路由
  groupRoutesByPath(routes: ServerApiFile[]) {
    const groups: Record<string, ServerApiFile[]> = {};
  
    routes.forEach(route => {
      // 生成分组键，去掉参数部分
      let groupPath = route.directory || '';
      
      // 从路径中移除所有参数部分
      const pathParts = groupPath.split('/').filter(part => part && !part.startsWith('['));
      
      // 如果路由名包含参数([id]、[platform]等)，则不包含在分组路径中
      if (route.name !== 'index' && !route.name.includes('[')) {
        pathParts.push(route.name);
      }
      
      groupPath = pathParts.join('/');
      
      if (!groups[groupPath]) {
        groups[groupPath] = [];
      }
      groups[groupPath].push(route);
    });
    
    return groups;
  }

  // 转换为驼峰命名
  toCamelCase(str: string) {
    return str.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase());
  }

  // 生成方法键名
  generateMethodKey(file: ServerApiFile) {
    if (file.params.length > 0) {
      // 对于有参数的路由，根据参数名称生成方法名
      const paramSuffix = file.params
        .map(param => `${param.charAt(0).toUpperCase()}${param.slice(1)}`)
        .join('');
      return `${file.method}By${paramSuffix}`;
    } else if (file.name === 'index') {
      // 对于 index 文件，使用 HTTP 方法作为键名
      return file.method;
    } else {
      // 对于普通路由，使用 HTTP 方法作为键名
      return file.method;
    }
  }

  // 生成API调用方法代码
  generateApiMethods() {
    const routes = this.apiFiles
      .sort((a, b) => a.routePath.localeCompare(b.routePath));
    
    const structure = this.buildNestedStructure(routes);
    
    return [
      `/* eslint-disable prettier/prettier */`,
      `import { request, ReturnValueType } from "./request"`,
      ...prefix('export const api = ', structure.print()),
    ];
  }

  // 生成API调用方法文件
  generate() {
    try {
      // 确保输出目录存在
      const outputDir = path.dirname(this.outputFile);
      if (!fs.existsSync(outputDir)) {
        fs.mkdirSync(outputDir, { recursive: true });
      }

      const { missing } = checkDependencies(config.METHOD_TEMPLATE_DIR);
      if (missing.length > 0) {
        console.error('❌ 缺少依赖:', missing.join(', '));
        console.error('请在 package.json 中添加以下依赖:');
        console.error(missing.map(dep => `  - ${dep}`).join('\n'));
        return;
      }

      copyTemplateFile(config.METHOD_TEMPLATE_DIR, outputDir);

      const apiCode = this.generateApiMethods();
      fs.writeFileSync(this.outputFile, apiCode.join(EOL), 'utf8');
      
      console.log('✅ API调用方法已成功生成到:', this.outputFile);
      console.log('📝 共生成', this.apiFiles.length, '个API方法');
      
      // 显示生成的API列表
      console.log('\n📋 生成的API方法列表:');
      this.apiFiles.forEach(file => {
        const paramsInfo = file.params.length > 0 ? ` (params: ${file.params.join(', ')})` : '';
        console.log(`  ${file.method.toUpperCase().padEnd(6)} ${file.routePath}${paramsInfo}`);
      });
      
    } catch (error: any) {
      console.error('❌ 生成API调用方法时发生错误:', error.message);
      console.error(error.stack);
    }
  }
}

/**
 * 生成 API 调用方法
 * @param dir 需要扫描的 API 目录
 * @param output 输出的文件夹
 */
export default function apim(dir: string, output: string) {
  const generator = new ApiMethodGenerator(dir, output);
  generator.generate();
}